home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 23 / AMIGAplus Sonderheft 23 (2000)(Falke)(DE)[!].iso / Tools / Text-Viewer / MSWordView / notes / ole / olelibexplanation / text0000.txt < prev   
Encoding:
Text File  |  1999-11-06  |  10.2 KB  |  370 lines

  1. Hi, 
  2.  
  3. Caolan copied me your email. Perhaps I can explain.
  4.  
  5. The code I wrote does parse the OLE tree fully in its original form. In
  6. fact I 
  7. attach a small C program, called OLEread.c which prints out the full
  8. tree 
  9. structure. 
  10.  
  11. Caolan tells me he only needs the "top level" entries from the OLE file,
  12. so in 
  13. the code I sent him, only those entries are extracted. Question is how
  14. to find 
  15. this "top level" linked list? Have a look at the recursive function
  16. "unravel" 
  17. in the C code.
  18.  
  19. If you start with the list of pps entries, one of them, usually the
  20. first, has 
  21. a "type" of 5 which means Root. All pps entries have pointers to
  22. previous, 
  23. next and directory pps entires. The Root pps entry will have a directory
  24. entry 
  25. which is effectively the "top" of the tree.
  26.  
  27. If you start with the pps pointed to by this Root->directory, and start
  28. to 
  29. follow it, it will unravel into a list of linked pps entries. However,
  30. the 
  31. list will consist of previous and next references and also some
  32. directory 
  33. entries. 
  34.  
  35. If all you want is the "top level" list, you simply DO NOT follow the 
  36. directory entries.
  37.  
  38. The code I attach DOES follow the directory entries just to print out
  39. the 
  40. tree, but it keeps track of what "level" of nesting you are at.
  41.  
  42. So a typical OLE doc may look like this
  43.  
  44.                   Root
  45.                    |
  46.                    3
  47.                   / \
  48.                  5   6- dir- 8
  49.                 / \   \     / \
  50.                9   8   10  4   2
  51.            
  52.  
  53. the top level list would be
  54.        9-5-8-3-6-10
  55.   and you ignore 4-8-2 as this is "nested" under 6.
  56.  
  57. Happy?
  58.  
  59. Andrew
  60. -----------------------------------------------------------------------
  61. Andrew Scriven
  62. Research and Engineering
  63. Electron Building, Windmill Hill, Whitehill Way, Swindon, SN5 6PB, UK
  64. Phone (44) 1793 896206, Fax (44) 1793 896251
  65. -----------------------------------------------------------------------
  66.  
  67. #include <stdio.h>
  68. #include <stdarg.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71. #include <malloc.h>
  72. #include <ctype.h>
  73. #include <sys/types.h>
  74. #include <assert.h>
  75.  
  76. #define MIN(a,b) ((a)<(b) ? (a) : (b))
  77. #define MAXBLOCKS 64
  78.  
  79. struct pps_block
  80.   {
  81.   char name[64];
  82.   int nsize;
  83.   char type;
  84.   struct pps_block *previous;
  85.   struct pps_block *next;
  86.   struct pps_block *directory;
  87.   long int start;
  88.   long int size;
  89.   int level;
  90.   int index;
  91.   };
  92.  
  93. typedef struct pps_block pps_entry;
  94.  
  95. char *pps_type[]={"","DIR ","FILE","","","ROOT"};
  96.  
  97. /* Routine prototypes */
  98. unsigned short int ShortInt(unsigned char* array);
  99. unsigned long int LongInt(unsigned char* array);
  100.  
  101. unsigned short int ShortInt(unsigned char* array)
  102. {
  103. union two_byte {
  104.  unsigned short int num;
  105.  char  ch[2];
  106.  } Short;
  107.  
  108. #ifndef INTEL
  109.   Short.ch[1] = *array++;
  110.   Short.ch[0] = *array;
  111. #else
  112.   Short.ch[0] = *array++;
  113.   Short.ch[1] = *array;
  114. #endif
  115. return Short.num;
  116.  
  117. }
  118.  
  119. unsigned long int LongInt(unsigned char* array)
  120. {
  121. union four_byte {
  122.  unsigned long int num;
  123.  char  ch[4];
  124.  } Long;
  125.  
  126. #ifndef INTEL
  127.   Long.ch[3] = *array++;
  128.   Long.ch[2] = *array++;
  129.   Long.ch[1] = *array++;
  130.   Long.ch[0] = *array;
  131. #else
  132.   Long.ch[0] = *array++;
  133.   Long.ch[1] = *array++;
  134.   Long.ch[2] = *array++;
  135.   Long.ch[3] = *array;
  136. #endif
  137. return Long.num;
  138. }
  139.  
  140. /* recurse to follow forward/backward list of root pps's */
  141. void unravel(pps_entry *pps_node, int level)
  142. {
  143.   if(pps_node->nsize ==0) return;
  144.   if(pps_node->previous != NULL) unravel(pps_node->previous,level);
  145.   pps_node->level = level;
  146.   printf("PPS %s: %*x: ->
  147. %s\n",pps_type[pps_node->type],level*3,pps_node->
  148. index,pps_node->name);
  149.   if(pps_node->directory != NULL) unravel(pps_node->directory,level+1);
  150.   if(pps_node->next != NULL) unravel(pps_node->next,level);
  151. }
  152.  
  153. int main(int argc, char **argv)
  154. {
  155.   FILE *input=NULL;
  156.   FILE *OLEfile=NULL;
  157.   FILE *sbfile=NULL;
  158.   FILE *infile=NULL;
  159.   char Target[64];
  160.   int debug=0, BlockSize=0,Offset=0;
  161.   int c,i,j,k,len,bytes;
  162.   char *s,*p,*t;
  163.   char *Block,*BDepot,*SDepot,*Depot,*Root;
  164.   char Name[64];
  165.   unsigned long int FilePos=0x00000000;
  166.   long int num_bbd_blocks;
  167.   long int root_list[MAXBLOCKS], sbd_list[MAXBLOCKS];
  168.   long int pps_size,pps_start=-1;
  169.   long int linkto;
  170.   int root_entry;
  171.   pps_entry **pps_list;
  172.  
  173.   if(argc < 2) {
  174.     fprintf(stderr,"No input file name\n");
  175.     exit (12);
  176.   }
  177.   fprintf(stderr,"File given was %s\n",argv[1]);
  178.   input = fopen(argv[1], "rb");
  179.   if(input==NULL) {
  180.     fprintf(stderr,"Error opening file %s\n",argv[1]);
  181.     exit (12);
  182.   }
  183.   if(argc < 3) {
  184.     fprintf(stderr,"Listing contents\n");
  185.     strncpy(Target,"UnLiKeLy",8);
  186.   } else {
  187.     strncpy(Target,argv[2],64);
  188.     fprintf(stderr,"Extracting %s...\n",Target);
  189.   }
  190.  
  191.   /* peek into file to guess file type */
  192.   c=getc(input);
  193.   ungetc(c,input);
  194.  
  195.   if(isprint(c)) {
  196.      fprintf(stderr,"File looks like a plain text file.\n");
  197.      return 8;
  198.   /* check for MS OLE wrapper */
  199.   } else if(c==0xd0) {
  200.      Block = malloc(512);
  201.      /* read header block */
  202.      if(fread(Block,512,1,input)!=1) {
  203.        fprintf(stderr,"1 ===========> Input file has faulty OLE
  204. format\n");
  205.         exit (5);
  206.      }
  207.      num_bbd_blocks=LongInt(Block+0x2c);
  208.      BDepot = malloc(512*num_bbd_blocks);
  209.      s = BDepot;
  210.      root_list[0]=LongInt(Block+0x30);
  211.      sbd_list[0]=LongInt(Block+0x3c);
  212.      if(debug) fprintf(stderr,"num_bbd_blocks %ld, root start %ld, sbd
  213. start 
  214. %ld\n",num_bbd_blocks,root_list[0],sbd_list[0]);
  215.  
  216.      /* read big block Depot */
  217.      for(i=0;i<(int)num_bbd_blocks;i++) {
  218.        FilePos = 512*(LongInt(Block+0x4c+(i*4))+1);
  219.        fseek(input,FilePos,SEEK_SET);
  220.        if(fread(s,512,1,input)!=1) {
  221.          fprintf(stderr,"2 ===========> Input file has faulty bbd\n");
  222.          exit (5);
  223.        }
  224.        s += 0x200;
  225.      }
  226.  
  227.      /* Extract the sbd block list */
  228.      for(len=1;len<MAXBLOCKS;len++){
  229.        sbd_list[len] = LongInt(BDepot+(sbd_list[len-1]*4));
  230.        if(sbd_list[len]==-2) break;
  231.      }
  232.      if(len>=MAXBLOCKS) fprintf(stderr,"Help too many sbd blocks\n");
  233.      SDepot = malloc(512*len);
  234.      s = SDepot;
  235.      /* Read in Small Block Depot */
  236.      for(i=0;i<len;i++) {
  237.        FilePos = 512 *(sbd_list[i]+1);
  238.        fseek(input,FilePos,SEEK_SET);
  239.        if(fread(s,512,1,input)!=1) {
  240.          fprintf(stderr,"3 ===========> Input file has faulty OLE
  241. format\n");
  242.          return 5;
  243.        }
  244.        s += 0x200;
  245.      }
  246.      /* Extract the root block list */
  247.      for(len=1;len<MAXBLOCKS;len++){
  248.        root_list[len] = LongInt(BDepot+(root_list[len-1]*4));
  249.        fprintf(stderr,"root block %d\n",len);
  250.        if(root_list[len]==-2) break;
  251.      }
  252.      if(len>=MAXBLOCKS) fprintf(stderr,"Help too many root blocks\n");
  253.      Root = malloc(512*len);
  254.      s = Root;
  255.      /* Read in Root stream data */
  256.      for(i=0;i<len;i++) {
  257.        FilePos = 512 *(root_list[i]+1);
  258.        fseek(input,FilePos,SEEK_SET);
  259.        if(fread(s,512,1,input)!=1) {
  260.          fprintf(stderr,"4 ===========> Input file has faulty OLE
  261. format\n");
  262.          return 5;
  263.        }
  264.        s += 0x200;
  265.      }
  266.  
  267.      /* assign space for pps list */
  268.      pps_list = malloc(len*4*sizeof(pps_entry *));
  269.      for(j=0;j<len*4;j++) pps_list[j] = malloc(sizeof(pps_entry));
  270.      /* Store pss entry details and look out for Root Entry */
  271.      for(j=0;j<len*4;j++) {
  272.        pps_list[j]->level = -1;
  273.        pps_list[j]->index = j;
  274.        s = Root+(j*0x80);
  275.        /* some pps names have first byte as an integer !!
  276.           so we make it visible so you can extract a named pps */
  277.        if(!isprint(*s)) *s = *s + 48;
  278.        pps_list[j]->nsize=ShortInt(s+0x40);
  279.        if(pps_list[j]->nsize == 0) continue;
  280.        for(p=pps_list[j]->name,t=s;t<s+pps_list[j]->nsize;t++) *p++ =
  281. *t++;
  282.        s+=0x42;
  283.        pps_list[j]->type = *s;
  284.        if(pps_list[j]->type == 5) {
  285.          root_entry = j; /* this is root */
  286.        }
  287.        s+=0x02;
  288.        linkto = LongInt(s);
  289.        if(linkto != -1) pps_list[j]->previous = pps_list[linkto];
  290.        else pps_list[j]->previous = NULL;
  291.        s+=0x04;
  292.        linkto = LongInt(s);
  293.        if(linkto != -1) pps_list[j]->next = pps_list[linkto];
  294.        else pps_list[j]->next = NULL;
  295.        s+=0x04;
  296.        linkto = LongInt(s);
  297.        if(linkto != -1) pps_list[j]->directory = pps_list[linkto];
  298.        else pps_list[j]->directory = NULL;
  299.        s+=0x28;
  300.        pps_list[j]->start = LongInt(s);
  301.        s+=0x04;
  302.        pps_list[j]->size = LongInt(s);
  303.      }
  304.  
  305.      /* go through the pps entries, tagging them with level number
  306.         use recursive routine to follow list starting at root entry */
  307.      unravel(pps_list[root_entry],0);
  308.  
  309.      /* go through the level 0 list looking for named entries */
  310.      for(j=0;j<len*4;j++) {
  311.        if(pps_list[j]->nsize == 0) continue; /* skip empty pps */
  312.        /* we mostly only want the top level (level 1) stuff, so
  313.           here we skip anything more deeply nested. */
  314.        if(pps_list[j]->level > 1) continue;
  315.        pps_start = pps_list[j]->start;
  316.        pps_size  = pps_list[j]->size;
  317.        OLEfile = NULL;
  318.        if(pps_list[j]->type==5) {  /* Root entry */
  319.          OLEfile = tmpfile();
  320.          sbfile = OLEfile;
  321.          if(debug) fprintf(stderr,"Reading sbFile %ld\n",pps_start);
  322.        }
  323.        else if(!strcmp(pps_list[j]->name,Target)) {
  324.          OLEfile=fopen("OLE.tmp","w+b");  /* try and open */
  325.          printf("Reading Target %s\n",Target);
  326.        }
  327.        if(pps_size<=0) OLEfile = NULL;
  328.        if(OLEfile == NULL) continue;
  329.        if(pps_size>=4096 | OLEfile==sbfile) {
  330.          Offset = 1;
  331.          BlockSize = 512;
  332.          infile = input;
  333.          Depot = BDepot;
  334.        } else {
  335.          Offset = 0;
  336.          BlockSize = 64;
  337.          infile = sbfile;
  338.          Depot = SDepot;
  339.        }
  340.        while(pps_start != -2) {
  341.          if(debug) fprintf(stderr,"Reading block %ld\n",pps_start);
  342.          FilePos = (pps_start+Offset)* BlockSize;
  343.          bytes = MIN(BlockSize,pps_size);
  344.          fseek(infile,FilePos,SEEK_SET);
  345.          if(fread(Block,bytes,1,infile)!=1) {
  346.            fprintf(stderr,"5 ===========> Input file has faulty OLE
  347. format\n");
  348.            exit (5);
  349.          }
  350.          fwrite(Block,bytes,1,OLEfile);
  351.          pps_start = LongInt(Depot+(pps_start*4));
  352.          pps_size -= BlockSize;
  353.          if(pps_size <= 0) pps_start=-2;
  354.        }
  355.        rewind(OLEfile);
  356.      }
  357.     for(j=0;j<len*4;j++) free(pps_list[j]);
  358.     free(pps_list);
  359.     free(Root);
  360.     free(BDepot);
  361.     free(Block);
  362.     fclose(input);
  363.     return 0;
  364.   } else {
  365.     /* not a OLE file! */
  366.     fprintf(stderr,"7 ===========> Input file is not an OLE file\n");
  367.     exit (8);
  368.   }
  369. }
  370.